/*
 * HitTheLines.cpp
 *
 *  Created on: 2011-03-29
 *      Author: lpieczkowski
 */

#include <HitTheLines.h>
#include <Screens/MainMenuScreen.h>
#include <SaveLoad.h>

using namespace Osp::App;
using namespace Osp::Base;
using namespace Osp::System;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;
using namespace Osp::Graphics::Opengl;
using namespace Osp::Base::Runtime;
using namespace Osp::Base::Utility;
using namespace Osp::Graphics;
using namespace Osp::Media;

HitTheLines* HitTheLines::instance = NULL;

HitTheLines*
HitTheLines::getInstance()
{
	if(!instance)
		instance = new HitTheLines();
	return instance;

}

HitTheLines::HitTheLines()
{

}

HitTheLines::~HitTheLines()
{
}

Application*
HitTheLines::CreateInstance(void) {
	// Create the instance through the singleton accessor

	return HitTheLines::getInstance();
}

bool
HitTheLines::OnAppInitializing(Osp::App::AppRegistry& appRegistry)
{
	GetAppFrame()->GetFrame()->SetOrientation(ORIENTATION_LANDSCAPE);
	GetAppFrame()->GetFrame()->AddTouchEventListener(*this);

	Initialize();

	return true;
}

//Initial timer - long delay so that loading can take place
void HitTheLines::OnForeground(void)
{
	globalTimer = new Timer();
	globalTimer->Construct(*this);

	if (globalTimer) {
		globalTimer->Start(500);
		UpdateLogic();
		Render();
	}
	else
	{
		AppLog("Initial timer error - terminating");
		Application::GetInstance()->Terminate();
	}
}

void
HitTheLines::Initialize(void)
{
	Osp::System::SystemTime::GetTicks(curTime);
	frameTime = 0;

	InitEGL();
	InitGL();

	//Randomize
	long long ticks;
	Osp::System::SystemTime::GetTicks(ticks);
	Osp::Base::Utility::Math::Srand((int) ticks);

	InitFonts();
	LoadCommonTextures();

	Vibrator.Construct();

	PushScreen(new MainMenuScreen());
}

bool
HitTheLines::InitEGL()
{
	eglBindAPI(EGL_OPENGL_ES_API);
	EGLint numConfigs = 1;
	EGLint eConfigList[] = {
	        EGL_RED_SIZE,       5,
	        EGL_GREEN_SIZE,     6,
	        EGL_BLUE_SIZE,      5,
	        EGL_DEPTH_SIZE,     16,
	        EGL_ALPHA_SIZE,     8,
	        EGL_STENCIL_SIZE,   EGL_DONT_CARE,
	        EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
	        EGL_NONE
	};
	eDisplay = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
	eglInitialize(eDisplay, NULL, NULL);
	eglChooseConfig(eDisplay, eConfigList, &eConfig, 1, &numConfigs);
	eSurface = eglCreateWindowSurface(eDisplay, eConfig,
			(EGLNativeWindowType) GetAppFrame()->GetFrame(), NULL);
	eContext = eglCreateContext(eDisplay, eConfig, EGL_NO_CONTEXT, NULL);
	eglMakeCurrent(eDisplay, eSurface, eSurface, eContext);
	return true;
}

bool
HitTheLines::InitGL()
{
	int x = 0, y = 0;
	GetAppFrame()->GetFrame()->GetBounds(x, y, globalHeight, globalWidth);
	glViewport(0, 0, globalWidth, globalHeight);
	glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnable(GL_BLEND);
	return true;
}

bool
HitTheLines::InitFonts()
{
	font.Construct(L"/Res/font/gfont.ttf", FONT_STYLE_PLAIN, 48);
	return true;
}

void
HitTheLines::LoadTexture(String filename, GLuint* texture)
{
	Bitmap* pBitmap = null;
	Image *pImage = new Image();
	pImage->Construct();

	pBitmap = pImage->DecodeN(filename, BITMAP_PIXEL_FORMAT_R8G8B8A8);
    int iWidth = pBitmap->GetWidth();
    int iHeight = pBitmap->GetHeight();
    updateTextureSize(iWidth, iHeight);
    pBitmap->Scale(Dimension(iWidth, iHeight));

	// Locking bitmap for direct access
	BufferInfo pixels;
	pBitmap->Lock(pixels);
	{
		glGenTextures(1, texture);
		glBindTexture(GL_TEXTURE_2D, *texture);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pBitmap->GetWidth(), pBitmap->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.pPixels );
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}
	pBitmap->Unlock();
	delete pBitmap;
	delete pImage;
}

void
HitTheLines::LoadCommonTextures()
{
	LoadTexture(L"/Res/Back-scaled.png", &backKeyTexture);
	LoadTexture(L"/Res/Back-glow2.png", &backKeyGlowTexture);
}

void
HitTheLines::updateTextureSize(int& iWidth, int& iHeight)
{
        int     i;
        bool bSizeToFit = false;

        if((iWidth != 1) && (iWidth & (iWidth - 1))) {
                i = 1;
                while((bSizeToFit ? 2 * i : i) < iWidth)
                        i *= 2;
                iWidth = i;
        }

        if((iHeight != 1) && (iHeight & (iHeight - 1))) {
                i = 1;
                while((bSizeToFit ? 2 * i : i) < iHeight)
                        i *= 2;
                iHeight = i;
        }
}

void
HitTheLines::UpdateLogic()
{
	ScreenStack.top()->UpdateLogic();
}

void
HitTheLines::RenderBackKey()
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	int t = int(curTime % 1024);
	double glow = Math::Sin((3.1415 * t) / 1024.0);

	glColor4f(glow, glow, glow, 1.0f);
	glBlendFunc(GL_ONE, GL_ONE);
	glBindTexture(GL_TEXTURE_2D, backKeyGlowTexture);
	glVertexPointer(2, GL_FLOAT, 0, backRectPoints);
	glTexCoordPointer(2, GL_FLOAT, 0, backRectCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBindTexture(GL_TEXTURE_2D, backKeyTexture);
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
	glVertexPointer(2, GL_FLOAT, 0, backRectPoints);
	glTexCoordPointer(2, GL_FLOAT, 0, backRectCoords);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

}

void
HitTheLines::Render()
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	ScreenStack.top()->Render();

	RenderBackKey();

	eglSwapBuffers(eDisplay, eSurface);

	prevTime = curTime;
	Osp::System::SystemTime::GetTicks(curTime);
	frameTime = (int)(curTime - prevTime);
}

void
HitTheLines::PointerPressed(float x, float y)
{
	//This is left blank since this class is not a screen itself
	AppLog("Something's wrong with touch pressed! \n");
}

void
HitTheLines::NavigateBack()
{
	CleanUp();
	Application::GetInstance()->Terminate();
}

void
HitTheLines::CleanUp()
{
	PopScreen(); // This must remove MainMenuScreen
	globalTimer->Cancel();
}

std::string
HitTheLines::GetScreenName()
{
	std::string name = "HitTheLines";
	return name;
}

void
HitTheLines::OnTouchPressed(const Osp::Ui::Control& source,
		const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo)
{
	float x = (2.0f * currentPosition.x / globalWidth) - 1.0f;
	float y = -((2.0f * currentPosition.y / globalHeight) - 1.0f);

	if(x > 0.8f && y < -0.7f)
	{
		ScreenStack.top()->NavigateBack();
	}
	else
	{
		ScreenStack.top()->PointerPressed(x, y);
	}
}

void
HitTheLines::OnTimerExpired(Osp::Base::Runtime::Timer& timer)
{
	UpdateLogic();
	Render();
	timer.Start(1);
}

void
HitTheLines::PushScreen(HitTheLines* newScreen)
{
	AppLog("Push screen\n");
	newScreen->Initialize();
	AppLog("After initialize in PushScreen");
	ScreenStack.push(newScreen);
	AppLog("After PushScreen");
}

void
HitTheLines::PopScreen()
{
	HitTheLines* scr = ScreenStack.top();
	scr->CleanUp();
	delete scr;
	ScreenStack.pop();
}

// Called when the application is terminating.
bool
HitTheLines::OnAppTerminating(Osp::App::AppRegistry& appRegistry, bool forcedTermination)
{
	// Save data if needed - AppRegistry

	return true;
}
